package de.cbf.cam.dsa.tavern.carte.model.persistence;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

import de.cbf.cam.dsa.tavern.carte.model.persistence.exceptions.PersistenceLoadException;
import de.cbf.cam.dsa.tavern.carte.model.persistence.exceptions.PersistenceSaveException;
import de.cbf.cam.dsa.tavern.carte.model.persistence.interfaces.IPersister;

public abstract class PersisterAbstract implements IPersister {	
	private	boolean 			unsavedChanges 	= false;
	private Collection<Object> 	objects 		= new ArrayList<Object>();
	/**
	 * 
	 */
	public PersisterAbstract() {		
	}
	
	protected abstract String 				getEventText();	
	protected abstract void 				setUIUnsavedChanges(boolean unsavedChanges);	
	protected abstract boolean 				doSaveObjects() 			throws PersistenceSaveException;
	protected abstract Collection<Object> 	doLoadObjects() 			throws PersistenceLoadException;
	protected abstract String				getMessageSaveComplete();
	protected abstract String				getMessageLoadComplete();
	
	/* (non-Javadoc)
	 * @see de.cbf.cam.dsa.tavern.cartegenerator.controller.IControllerPersistIngredients#hasUnsavedChanges()
	 */
	@Override
	public boolean hasUnsavedChanges() {
		return unsavedChanges;
	}
	
	protected void setUnsavedChanges(boolean unsavedChanges) {
		this.unsavedChanges = unsavedChanges;
		setUIUnsavedChanges(unsavedChanges);		
	}

	public void saveEntityObjects(){
		saveObjects();
	}
	
	protected void saveObjects(){
		try {
			if(doSaveObjects()){
				setUnsavedChanges(false);
				notifyUserSaveComplete();
			}
		} catch (PersistenceSaveException e) {			
			notifyException(e.getLocalizedMessage());
		}
	}	
	
	public void loadEntityObjects(){
		loadObjects();
	}
	
	protected void loadObjects(){
		Collection<Object> loads;
		try {
			loads = doLoadObjects();
			if( ! loads.equals(objects)){
				objects.clear();
				objects.addAll(loads);				
				notifyObjectsChanged();
				notifyUserLoadComplete();			
				setUnsavedChanges(false);
			}
		} catch (PersistenceLoadException e) {			
			notifyException(e.getLocalizedMessage());
		}		
	}
	
	public Collection<Object> getEntityObjects() {
		return getObjects();
	}

	protected Collection<Object> getObjects() {
		return objects;
	}

	public void setEntityObjects(Collection<? extends Object> values){
		setObjects(values);
	}
	
	protected void setObjects(Collection<? extends Object> values) {
		if( values == null || values.equals(objects))return;
		//
		objects.clear();
		Iterator<? extends Object> iterator = values.iterator();
		while (iterator.hasNext()) {
			Object object = (Object) iterator.next();
			objects.add(object);			
		}
		setUnsavedChanges(true);
		notifyObjectsChanged();							
	}
			
	protected Collection<ActionListener> objectsChangedListeners = new ArrayList<ActionListener>();
	public boolean registerObjectsChangedListener(ActionListener listener){
		return objectsChangedListeners.add(listener);
	}
	
	public boolean deRegisterObjectsChangedListener(ActionListener listener){
		return objectsChangedListeners.remove(listener);
	}	
	protected void notifyObjectsChanged(){
		ActionEvent event = new ActionEvent(PersisterAbstract.this, ActionEvent.ACTION_PERFORMED, getEventText());
		for (ActionListener listener : objectsChangedListeners) {
			listener.actionPerformed(event);
		}
	}
	
	protected Collection<ActionListener> exceptionListeners = new ArrayList<ActionListener>();	
	public boolean registerExceptionListener(ActionListener listener){
		return exceptionListeners.add(listener);
	}
	
	public boolean deRegisterExceptionListener(ActionListener listener){
		return exceptionListeners.remove(listener);
	}	
	protected void notifyException(String message){	
		ActionEvent event = new ActionEvent(PersisterAbstract.this, ActionEvent.ACTION_PERFORMED,message);		
		for (ActionListener listener : exceptionListeners) {
			listener.actionPerformed(event);
		}
	}

	private Collection<ActionListener> loadCompletedListeners = new ArrayList<ActionListener>();
	public boolean registerLoadCompletedListener(ActionListener listener){
		return loadCompletedListeners.add(listener);
	}
	public boolean deRegisterLoadCompletedListener(ActionListener listener){
		return loadCompletedListeners.remove(listener);
	}
	protected void notifyUserLoadComplete() {
		ActionEvent event = new ActionEvent(PersisterAbstract.this, ActionEvent.ACTION_PERFORMED, getMessageLoadComplete());
		for (ActionListener listener : loadCompletedListeners) {
			listener.actionPerformed(event);
		}
	}
	private Collection<ActionListener> SaveCompletedListeners = new ArrayList<ActionListener>();
	public boolean registerSaveCompletedListener(ActionListener listener){
		return SaveCompletedListeners.add(listener);
	}
	public boolean deRegisterSaveCompletedListener(ActionListener listener){
		return SaveCompletedListeners.remove(listener);
	}
	protected void notifyUserSaveComplete() {
		ActionEvent event = new ActionEvent(PersisterAbstract.this, ActionEvent.ACTION_PERFORMED, getMessageSaveComplete());
		for (ActionListener listener : SaveCompletedListeners) {
			listener.actionPerformed(event);
		}
	}
}
